import Cat2DocButton from "./elements/button";
import imgDrag from '../assets/images/drag.svg'
import Cat2DocText from "./elements/text";
import Cat2DocImg from "./elements/img";
import Cat2DocTable from "./elements/table";
import Cat2DocPre from "./elements/pre";

class Cat2DocTools {
    #toolsDiv = null;
    #currentRowElement = null;
    #dragButton = null;
    #buttons = [];
    #rowDragEnter = this.#handleRowDragEnter.bind(this);
    #rowDragOver = this.#handleRowDragOver.bind(this);
    #dragButtonDragStart = this.#handleDragButtonDragStart.bind(this);
    #dragButtonDrag = this.#handleDragButtonDrag.bind(this);
    #dragButtonDragOver = this.#handleDragButtonDragOver.bind(this);

    // 工具中元素的属性标记
    static #INTERNAL_FLAT = 'tools-internal';
    constructor(parentElement, x, y) {
        if(parentElement) {
            this.#toolsDiv = Cat2DocTools.#createToolsDiv(parentElement);
            this.setPos(x, y);
            // 设置拖拽按钮
            this.#dragButton = this.createButton({
                url: imgDrag,
                group: Cat2DocTools.#INTERNAL_FLAT,
                className: 'c2d-tools-button',
                style: {
                    cursor: 'move'
                }
            });
            this.#dragButton.$el.addEventListener('dragstart', this.#dragButtonDragStart);
            this.#dragButton.$el.addEventListener('drag', this.#dragButtonDrag);
            this.#dragButton.$el.addEventListener('dragend', this.#dragButtonDragOver);
        }
    }
    /** 释放 */
    destory() {
        if(this.#toolsDiv) {
            this.#toolsDiv.remove();
            this.#toolsDiv = null;
        }
        if(this.#dragButton) {
            this.#dragButton.$el.removeEventListener('dragstart', this.#dragButtonDragStart);
            this.#dragButton.$el.removeEventListener('drag', this.#dragButtonDrag);
            this.#dragButton.$el.removeEventListener('dragend', this.#dragButtonDragOver);
            this.#dragButton.destory();
            this.#dragButton = null;
        }
    }
    get left() {
        return this.#toolsDiv.offsetLeft;
    }
    get top() {
        return this.#toolsDiv.offsetTop;
    }
    get width() {
        return this.#toolsDiv.offsetWidth;
    }
    get height() {
        return this.#toolsDiv.offsetHeight;
    }
    get $el() {
        return this.#toolsDiv;
    }
    /** 重设 */
    reset() {
        this.setPos(this.left, 0);
        this.hide();
    }
    /** 显示tools */
    show() {
        this.#toolsDiv.style.backgroundColor = '';
        this.#toolsDiv.style.display = 'inline-flex';
    }
    /** 隐藏tools */
    hide() {
        this.#toolsDiv.style.backgroundColor = '#0000';
        this.#toolsDiv.style.display = 'none';
    }
    /** 移动tools到目标位置 */
    moveTo(targetEle) {
        let opts;
        if(Cat2DocText.isType(targetEle)) opts = Cat2DocText.getTools(targetEle);
        if(Cat2DocImg.isType(targetEle)) opts = Cat2DocImg.getTools(targetEle);
        if(Cat2DocTable.isType(targetEle)) opts = Cat2DocTable.getTools(targetEle);
        if(Cat2DocPre.isType(targetEle)) opts = Cat2DocPre.getTools(targetEle);
        if(opts) {
            let left = this.#toolsDiv.offsetLeft + this.#toolsDiv.offsetWidth;
            this.clearButtons();
            opts.buttons = opts.buttons || [];
            opts.buttons.forEach(b=>{
                this.#buttons.push(this.createButton(b));
            });
            left -= this.#toolsDiv.offsetWidth;
            this.#toolsDiv.style.left = left + 'px';
        }
        this.#currentRowElement = targetEle;
        this.#slideTools();
    }
    /** 设置tools位置 */
    setPos(x, y) {
        this.#toolsDiv.style.left = x + 'px';
        this.#toolsDiv.style.top = y + 'px';
    }
    /** 创建工具按钮 */
    createButton(options) {
        let button = new Cat2DocButton(null, options);
        if(this.#dragButton){
            this.#toolsDiv.insertBefore(button.$el, this.#dragButton.$el);
        } else {
            this.#toolsDiv.appendChild(button.$el);
        }
        return button;
    }
    /** 清除所有自定义按钮 */
    clearButtons() {
        this.#buttons.forEach(b=>b.destory());
        this.#buttons = [];
    }
    /** 滑动tools工具块div到当前行 */
    #slideTools() {
        if(!this.#currentRowElement) return;
        let top = parseInt(this.#toolsDiv.offsetTop) || 0;
        let targetHeight = this.#currentRowElement.offsetTop - (this.#currentRowElement.parentNode?this.#currentRowElement.parentNode.scrollTop:0);
        if (top !== targetHeight) {
            targetHeight = top - targetHeight;
            const y = Math.max(this.top -  targetHeight/Math.abs(targetHeight) * Math.ceil(Math.abs(targetHeight)/20), 0);
            this.setPos(this.left, y);
            y>0 && requestAnimationFrame(this.#slideTools.bind(this));
        }
    }
    /** 拖动按钮拖动开始事件 */
    #handleDragButtonDragStart(event) {
        // 如果文档可以编辑，在拖动开始时禁止编辑状态
        if(!this.#currentRowElement || !this.#currentRowElement.parentNode) return;
        if(this.#currentRowElement.parentNode.hasAttribute('contenteditable')){
            this.#currentRowElement.parentNode.setAttribute('contenteditable', false);
            this.#currentRowElement.parentNode.setAttribute('temp-contenteditable', true)
        }
        // 设置所有文档中的段落监听拖拽事件
        this.#currentRowElement.parentNode.childNodes.forEach(c=>{
            c.draggable = true;
            c.addEventListener('dragenter', this.#rowDragEnter);
            c.addEventListener('dragover', this.#rowDragOver);
        });
        this.#currentRowElement.style.backgroundColor='rgb(217, 236, 255)';

        let dt = event.dataTransfer;
        dt.effectAllowed = 'move';
        dt.setDragImage(this.#currentRowElement, 10, 10);
    }
    /** 拖动按钮拖动中事件 */
    #handleDragButtonDrag(event) {
        event.preventDefault();
    }
    /** 拖动按钮拖动结束事件 */
    #handleDragButtonDragOver(event) {
        if(!this.#currentRowElement || !this.#currentRowElement.parentNode) return;
        // 移除所有文档中的段落监听拖拽事件
        this.#currentRowElement.parentNode.childNodes.forEach(c=>{
            c.draggable = false;
            c.removeEventListener('dragenter', this.#rowDragEnter);
            c.removeEventListener('dragover', this.#rowDragOver);
        });
        // 如果文档可以编辑，在拖动结束后回复编辑状态
        if(this.#currentRowElement.parentNode.hasAttribute('temp-contenteditable')){
            this.#currentRowElement.parentNode.setAttribute('contenteditable', true);
            this.#currentRowElement.parentNode.removeAttribute('temp-contenteditable')
        }
        this.#currentRowElement.style.backgroundColor='';
        event.stopPropagation();
    }
    /** 拖动文章段落拖动开始事件 */
    #handleRowDragEnter(event) {
        const rootElement = this.#currentRowElement.parentNode;
        const ele = getPOfDoc(event.target);
        if(ele && ele !== this.#currentRowElement) {
            // 所有文档对象转为数组
            let liArray = Array.from(rootElement.childNodes);
            // 获取到拖动元素的下标
            let currentIndex = liArray.indexOf(this.#currentRowElement);
            // 获取到目标元素的下标
            let targetIndex = liArray.indexOf(ele);
            // 重新设置拖动元素位置
            if(currentIndex<targetIndex){
                if(ele.nextElementSibling) {
                    rootElement.insertBefore(this.#currentRowElement, ele.nextElementSibling)
                } else {
                    ele.insertAdjacentElement('afterend', this.#currentRowElement);
                }
            }else{
                rootElement.insertBefore(this.#currentRowElement, ele)
            }
            event.stopPropagation();
        }
    }
    /** 拖动文章段落拖动结束事件 */
    #handleRowDragOver(event) {
        event.preventDefault();
    }

    /** 创建tools块div */
    static #createToolsDiv(parent) {
        let div = document.createElement('div');
        div.className = 'c2d-tools';
        div.style.zIndex = '2';
        div.style.position = 'absolute';
        div.style.backgroundColor = '#0000';
        div.style.display = 'none';
        parent.appendChild(div);
        return div;
    }
}
/** 获得文档根节点 */
function getPOfDoc(ele) {
    if(!ele) {
        return ele;
    } else if(ele.parentNode.classList.contains('c2d-doc')) {
        return ele;
    } else {
        return getPOfDoc(ele.parentNode);
    }
}

export default Cat2DocTools;
